#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>

#include "Task.hpp"

template<class T>
class BlockQueue
{
    static const int defaultNum = 20;
public:
    BlockQueue(int maxCapacity = defaultNum)
        :_maxCapacity(maxCapacity)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_c_cond, nullptr);
        pthread_cond_init(&_p_cond, nullptr);
        // _lowWater = defaultNum / 3;
        // _hightWater = defaultNum * 2 / 3;
    }

    T pop()
    {
        pthread_mutex_lock(&_mutex);
        while(_q.empty()) pthread_cond_wait(&_c_cond, &_mutex);

        T out = _q.front();
        _q.pop();

        // if(_q.size() < _lowWater)   // 作为消费者，低于水位线，唤醒生产者
             pthread_cond_signal(&_p_cond);  
        
        pthread_mutex_unlock(&_mutex);
        return out;
    }

    void push(const T& in)
    {
        pthread_mutex_lock(&_mutex);
        while(_q.size() == _maxCapacity) 
            pthread_cond_wait(&_p_cond, &_mutex);   // 调用时自动释放锁
        
        // 队列未满，没有条件等待
        _q.push(in);    // 生产之前需要检查临界资源是否就绪

        // if(_q.size() > _hightWater)     // 作为生产者，高于水位线，唤醒消费者
             pthread_cond_signal(&_c_cond);  

        pthread_mutex_unlock(&_mutex);
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_c_cond);
        pthread_cond_destroy(&_p_cond);
    }
private:
    std::queue<T> _q;   // CP的共享资源
    int _maxCapacity;
    pthread_mutex_t _mutex;
    pthread_cond_t _c_cond;
    pthread_cond_t _p_cond;
    // int _lowWater;
    // int _hightWater;
};